package xyz.yq56.glue_tool.actions;

import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.intellij.execution.filters.TextConsoleBuilder;
import com.intellij.execution.filters.TextConsoleBuilderFactory;
import com.intellij.execution.impl.ConsoleViewImpl;
import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.EditorSettings;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.psi.PsiFile;
import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentFactory;
import com.intellij.ui.content.ContentManager;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;

import xyz.yq56.glue_tool.config.GlueToolConfig;
import xyz.yq56.glue_tool.icon.Icons;

/**
 * @author yi qiang
 * @date 2023-11-22 14:23:42
 */
public class GlueToolAction extends AnAction {
    private static final GlueToolConfig.Config config = GlueToolConfig.getInstance().getState();
    private static final Logger LOGGER = Logger.getInstance(GlueToolAction.class);

    public static void doRequest(Project project, String filePath, String url) {
        try {
            assert config != null;

            Map<String, Object> params = new HashMap<>();
            params.put("source", Files.readString(Path.of(filePath)));
            params.put("param", null);
            String data = new ObjectMapper().writeValueAsString(params);

            Request request = new Request.Builder()
                    .url(url + (url.endsWith("/") ? "" : "/") + "yapi/glue/execute")
                    .addHeader("live-yapi-access-key", Optional.ofNullable(config.items.get(url)).orElse(""))
                    .post(RequestBody.create(
                            MediaType.parse("application/json"), data))
                    .build();

            Response response = callRequest(project, data, request);
            if (response == null) {
                return;
            }

            if (inputKeyThenRetryWhen401(project, filePath, url, response)) {
                return;
            }

            showToolWindow(project, data, request, response.body().string());
        } catch (Exception ex) {
            LOGGER.error(ex.getMessage());
        }
    }

    @Nullable
    private static Response callRequest(Project project, String data, Request request) {
        Response response;
        try {
            response = new OkHttpClient().newCall(request).execute();
        } catch (Exception e) {
            // 老是超时,这里捕获异常
            showToolWindow(project, data, request, e.getMessage());
            return null;
        }
        return response;
    }

    private static boolean inputKeyThenRetryWhen401(Project project, String filePath, String url, Response response) {
        if (response.code() == 401) {
            String accessKey = Messages.showInputDialog(
                    project,
                    "Please input yapiAccessKey,and try again",
                    "Info",
                    Messages.getInformationIcon()
            );
            if (accessKey != null) {
                assert config != null;
                config.items.put(url, accessKey);
                //重试请求
                doRequest(project, filePath, url);
            }
            return true;
        }
        return false;
    }

    private static void showToolWindow(Project project, String data, Request request, String response) {
        ConsoleViewImpl consoleView = createConsoleView(project);
        consoleView.print(
                "URL:\n" + request.urlString() + "\n\n参数:\n" + data + "\n\n响应:\n" + response,
                ConsoleViewContentType.NORMAL_OUTPUT
        );

        ContentFactory instance = ContentFactory.SERVICE.getInstance();
        Content content = instance.createContent(consoleView, "Log", false);
        content.setCloseable(true);
        content.setIcon(Icons.PRETTY_PRINT);
        ToolWindow toolWindow = ToolWindowManager.getInstance(project).getToolWindow("GlueTool");
        if (toolWindow != null) {
            toolWindow.show();
            ContentManager contentManager = toolWindow.getContentManager();
            contentManager.addContent(content);
            //设置选中
            contentManager.setSelectedContent(content);
        } else {
            Messages.showMessageDialog(project, "ToolWindow does not exist", "Info", Messages.getInformationIcon());
        }
    }

    private static ConsoleViewImpl createConsoleView(Project project) {
        TextConsoleBuilder consoleBuilder = TextConsoleBuilderFactory.getInstance().createBuilder(project);
        final ConsoleViewImpl console = (ConsoleViewImpl) consoleBuilder.getConsole();
        // init editor
        console.getComponent();

        EditorSettings settings = console.getEditor().getSettings();
        settings.setLineNumbersShown(true);
        settings.setFoldingOutlineShown(true);
        settings.setAutoCodeFoldingEnabled(true);

        return console;
    }

    @Override
    public void actionPerformed(@NotNull AnActionEvent e) {
        String filePath = Optional.ofNullable(e.getData(CommonDataKeys.PSI_FILE))
                .map(PsiFile::getVirtualFile)
                .map(VirtualFile::getPath).orElse("");

        LOGGER.info("当前文件路径: " + filePath);

        assert config != null;

        config.items.forEach((k, v) -> LOGGER.info(k + " : " + v));

        JBPopupFactory.getInstance()
                .createPopupChooserBuilder(new ArrayList<>(config.items.keySet()))
                .setItemChosenCallback(url -> doRequest(e.getProject(), filePath, url))
                .createPopup()
                .showInBestPositionFor(e.getDataContext());
    }
}
